package com.bosicloud.cmb.ibp;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.bosicloud.cmb.ibp.commom.constant.IbpError;
import com.bosicloud.cmb.ibp.commom.dto.UnionResult;
import com.bosicloud.cmb.ibp.commom.dto.ValidateMessage;
import com.bosicloud.cmb.ibp.commom.exception.BusinessException;
import com.bosicloud.cmb.ibp.commom.exception.RemoteMethodArgumentException;
import com.bosicloud.cmb.ibp.commom.exception.ServiceException;
import com.bosicloud.cmb.ibp.commom.exception.UnknowException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.PersistenceException;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Jack Peng / ziliang.peng@bosicloud.com
 */
@Slf4j
public abstract class AbstractIbpExceptionHandler {

    public Object transferException(Exception e) {

        if (e instanceof FeignException) {
            FeignException fe = (FeignException) e;
            return UnionResult.builder()
                    .status(UnionResult.StatusEnum.InnerError.code())
                    .msg(IbpError.IBP_FEIGN.getTips())
                    .data(fe.getMessage())
                    .build();

        }

        if (e instanceof BusinessException) {
            return UnionResult
                    .builder()
                    .status(UnionResult.StatusEnum.Fail.code())
                    .msg(e.getMessage())
                    .build();
        }

        if (e instanceof ServiceException) {
            ServiceException se = (ServiceException) e;
            return UnionResult
                    .builder()
                    .status(se.getErrorCode())
                    .msg(e.getMessage())
                    .data(e.getMessage())
                    .build();
        }

        if (e instanceof RemoteMethodArgumentException) {
            RemoteMethodArgumentException rme = (RemoteMethodArgumentException) e;
            return UnionResult.builder()
                    .status(UnionResult.StatusEnum.FormFail.code())
                    .msg(JSON.toJSONString(rme.getData()))
                    .data(rme.getData())
                    .build();
        }

        if (e instanceof HystrixRuntimeException) {
            HystrixRuntimeException exception = (HystrixRuntimeException) e;
            HystrixRuntimeException.FailureType type = exception.getFailureType();

            String message = e.getLocalizedMessage();
            if (type == HystrixRuntimeException.FailureType.TIMEOUT) {
                message = IbpError.BA_HYSTIX_TIME_OUT.getTips();
            } else if (type == HystrixRuntimeException.FailureType.SHORTCIRCUIT) {
                message = IbpError.BA_HYSTIX_SHORTCIRCUIT.getTips();
            }
            return UnionResult.builder()
                    .status(UnionResult.StatusEnum.HystrixDegradation.code())
                    .msg(message)
                    .data(message)
                    .build();
        }

        if (e instanceof UnknowException) {
            UnknowException ue = (UnknowException) e;
            return UnionResult.builder()
                    .status(UnionResult.StatusEnum.InnerError.code())
                    .msg(ue.getMessage())
                    .data(ue.getData())
                    .build();
        }

        if (e instanceof MethodArgumentNotValidException) {
            BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            UnionResult result = new UnionResult();
            result.setStatus(UnionResult.StatusEnum.FormFail.code());

            List<ValidateMessage> list = new ArrayList<>();
            for (FieldError fieldError : bindingResult.getFieldErrors()) {

                list.add(ValidateMessage.builder().
                        defaultMessage(fieldError.getDefaultMessage()).
                        field(fieldError.getField()).
                        objectName(fieldError.getObjectName()).build());
            }
            result.setMsg(JSONArray.toJSONString(list));
            result.setData(list);
            return result;
        }

        if (e instanceof NullPointerException) {
            return UnionResult.builder()
                    .status(UnionResult.StatusEnum.InnerError.code())
                    .msg(IbpError.BA_NULL_POINT.getTips())
                    .data(e.getMessage())
                    .build();
        }
        if (e instanceof PersistenceException) {
            PersistenceException se = (PersistenceException) e;
            return UnionResult
                    .builder()
                    .status(UnionResult.StatusEnum.InnerError.code())
                    .msg(IbpError.PERSISTENCE_EXCEPTION.getTips())
                    .data(IbpError.PERSISTENCE_EXCEPTION.getTips())
                    .build();
        }

        if (e instanceof SQLException) {
            return UnionResult
                    .builder()
                    .status(UnionResult.StatusEnum.InnerError.code())
                    .msg(IbpError.DB_EXCEPTION.getTips())
                    .data(IbpError.DB_EXCEPTION.getTips())
                    .build();
        }


        if (e instanceof DataAccessException) {
            return UnionResult
                    .builder()
                    .status(UnionResult.StatusEnum.InnerError.code())
                    .msg(IbpError.DB_EXCEPTION.getTips())
                    .data(IbpError.DB_EXCEPTION.getTips())
                    .build();
        }
        log.warn("未处理异常脱敏异常信息.", e);

        return UnionResult
                .builder()
                .status(UnionResult.StatusEnum.InnerError.code())
                .msg(IbpError.UNKNOW_EXCEPTION.getTips())
                .build();
    }
}

